//--------------------------------------------------------------------------------------
// File: simplePathTracing.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
#include "DXUT.h"
#include "DXUTgui.h"
#include "DXUTmisc.h"
#include "DXUTCamera.h"
#include "DXUTSettingsDlg.h"
#include "SDKmisc.h"
#include "SDKmesh.h"
#include "resource.h"

#include "src/camera.h"
#include "src/film.h"

//#define DEBUG_VS   // Uncomment this line to debug D3D9 vertex shaders 
//#define DEBUG_PS   // Uncomment this line to debug D3D9 pixel shaders 

#define WIDTH 640
#define HEIGHT 480

//--------------------------------------------------------------------------------------
// Global variables
//--------------------------------------------------------------------------------------
CDXUTDialogResourceManager  g_DialogResourceManager; // manager for shared resources of dialogs
CD3DSettingsDlg             g_SettingsDlg;          // Device settings dialog
CDXUTTextHelper*            g_pTxtHelper = NULL;
CDXUTDialog                 g_HUD;                  // dialog for standard controls
CDXUTDialog                 g_SampleUI;             // dialog for sample specific controls

// Direct3D 9 resources
ID3DXFont*                  g_pFont9 = NULL;
ID3DXSprite*                g_pSprite9 = NULL;
ID3DXSprite*                g_pSpriteTex = NULL;
ID3DXEffect*                g_pEffect9 = NULL;
// Final Framebuffer texture
LPDIRECT3DTEXTURE9          g_pFrameTexture = 0;

SceneManager		        g_SceneManager;
Camera						g_ProjectCamera;
CFilm						g_Film;
//--------------------------------------------------------------------------------------
// UI control IDs
//--------------------------------------------------------------------------------------
#define IDC_TOGGLEFULLSCREEN    1
#define IDC_TOGGLEREF           2
#define IDC_CHANGEDEVICE        3


//--------------------------------------------------------------------------------------
// Forward declarations 
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing,
                          void* pUserContext );
void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext );
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext );
void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext );
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext );

bool CALLBACK IsD3D9DeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat,
                                      bool bWindowed, void* pUserContext );
HRESULT CALLBACK OnD3D9CreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                     void* pUserContext );
HRESULT CALLBACK OnD3D9ResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                    void* pUserContext );
void CALLBACK OnD3D9FrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext );
void CALLBACK OnD3D9LostDevice( void* pUserContext );
void CALLBACK OnD3D9DestroyDevice( void* pUserContext );

void InitApp();
void RenderText(double fTime, float fElapsedTime);


//--------------------------------------------------------------------------------------
// Entry point to the program. Initializes everything and goes into a message processing 
// loop. Idle time is used to render the scene.
//--------------------------------------------------------------------------------------
int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow )
{
    // Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

    // DXUT will create and use the best device (either D3D9 or D3D10) 
    // that is available on the system depending on which D3D callbacks are set below

    // Set DXUT callbacks
    DXUTSetCallbackMsgProc( MsgProc );
    DXUTSetCallbackKeyboard( OnKeyboard );
    DXUTSetCallbackFrameMove( OnFrameMove );
    DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );

    DXUTSetCallbackD3D9DeviceAcceptable( IsD3D9DeviceAcceptable );
    DXUTSetCallbackD3D9DeviceCreated( OnD3D9CreateDevice );
    DXUTSetCallbackD3D9DeviceReset( OnD3D9ResetDevice );
    DXUTSetCallbackD3D9DeviceLost( OnD3D9LostDevice );
    DXUTSetCallbackD3D9DeviceDestroyed( OnD3D9DestroyDevice );
    DXUTSetCallbackD3D9FrameRender( OnD3D9FrameRender );

    InitApp();
    DXUTInit( true, true, NULL ); // Parse the command line, show msgboxes on error, no extra command line params
    DXUTSetCursorSettings( true, true );
    DXUTCreateWindow( L"simplePathTracing" );
    DXUTCreateDevice( true, WIDTH, HEIGHT );
    DXUTMainLoop(); // Enter into the DXUT render loop

    return DXUTGetExitCode();
}


//--------------------------------------------------------------------------------------
// Initialize the app 
//--------------------------------------------------------------------------------------
void InitApp()
{
    g_SettingsDlg.Init( &g_DialogResourceManager );
    g_HUD.Init( &g_DialogResourceManager );
    g_SampleUI.Init( &g_DialogResourceManager );

    g_HUD.SetCallback( OnGUIEvent ); int iY = 10;
    g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 );
    g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, iY += 24, 125, 22, VK_F3 );
    g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, iY += 24, 125, 22, VK_F2 );

    g_SampleUI.SetCallback( OnGUIEvent ); iY = 10;
}


//--------------------------------------------------------------------------------------
// Render the help and statistics text. This function uses the ID3DXFont interface for 
// efficient text rendering.
//--------------------------------------------------------------------------------------
void RenderText(double fTime, float fElapsedTime)
{
    g_pTxtHelper->Begin();
    g_pTxtHelper->SetInsertionPos( 5, 5 );
    g_pTxtHelper->SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
    g_pTxtHelper->DrawTextLine( DXUTGetFrameStats( DXUTIsVsyncEnabled()|1 ) );
    g_pTxtHelper->DrawTextLine( DXUTGetDeviceStats() );
    WCHAR timeInfo[200];
    swprintf(timeInfo, L"fTime: %f, fElapsedTime: %f\n", fTime, fElapsedTime);
    g_pTxtHelper->DrawTextLine(timeInfo);
    g_pTxtHelper->End();
}


//--------------------------------------------------------------------------------------
// Rejects any D3D9 devices that aren't acceptable to the app by returning false
//--------------------------------------------------------------------------------------
bool CALLBACK IsD3D9DeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat,
                                      D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext )
{
    // Skip backbuffer formats that don't support alpha blending
    IDirect3D9* pD3D = DXUTGetD3D9Object();
    if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
                                         AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING,
                                         D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
        return false;

    // No fallback defined by this app, so reject any device that 
    // doesn't support at least ps2.0
    if( pCaps->PixelShaderVersion < D3DPS_VERSION( 2, 0 ) )
        return false;

    return true;
}


//--------------------------------------------------------------------------------------
// Called right before creating a D3D9 or D3D10 device, allowing the app to modify the device settings as needed
//--------------------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext )
{
    if( pDeviceSettings->ver == DXUT_D3D9_DEVICE )
    {
        IDirect3D9* pD3D = DXUTGetD3D9Object();
        D3DCAPS9 Caps;
        pD3D->GetDeviceCaps( pDeviceSettings->d3d9.AdapterOrdinal, pDeviceSettings->d3d9.DeviceType, &Caps );

        // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
        // then switch to SWVP.
        if( ( Caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ) == 0 ||
            Caps.VertexShaderVersion < D3DVS_VERSION( 1, 1 ) )
        {
            pDeviceSettings->d3d9.BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
        }
    }

    // For the first device created if its a REF device, optionally display a warning dialog box
    static bool s_bFirstTime = true;
    if( s_bFirstTime )
    {
        s_bFirstTime = false;
        if( ( DXUT_D3D9_DEVICE == pDeviceSettings->ver && pDeviceSettings->d3d9.DeviceType == D3DDEVTYPE_REF ) ||
            ( DXUT_D3D10_DEVICE == pDeviceSettings->ver &&
              pDeviceSettings->d3d10.DriverType == D3D10_DRIVER_TYPE_REFERENCE ) )
            DXUTDisplaySwitchingToREFWarning( pDeviceSettings->ver );
    }

    return true;
}


//--------------------------------------------------------------------------------------
// Create any D3D9 resources that will live through a device reset (D3DPOOL_MANAGED)
// and aren't tied to the back buffer size
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D9CreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                     void* pUserContext )
{
    HRESULT hr;

    V_RETURN( g_DialogResourceManager.OnD3D9CreateDevice( pd3dDevice ) );
    V_RETURN( g_SettingsDlg.OnD3D9CreateDevice( pd3dDevice ) );

    V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET,
                              OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
                              L"Arial", &g_pFont9 ) );

    return S_OK;
}


//--------------------------------------------------------------------------------------
// Create any D3D9 resources that won't live through a device reset (D3DPOOL_DEFAULT) 
// or that are tied to the back buffer size 
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D9ResetDevice( IDirect3DDevice9* pd3dDevice,
                                    const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
{
    HRESULT hr;

    V_RETURN( g_DialogResourceManager.OnD3D9ResetDevice() );
    V_RETURN( g_SettingsDlg.OnD3D9ResetDevice() );

    if( g_pFont9 ) V_RETURN( g_pFont9->OnResetDevice() );
    if( g_pEffect9 ) V_RETURN( g_pEffect9->OnResetDevice() );

    V_RETURN( D3DXCreateSprite( pd3dDevice, &g_pSpriteTex ) );

    V_RETURN( D3DXCreateSprite( pd3dDevice, &g_pSprite9 ) );
    g_pTxtHelper = new CDXUTTextHelper( g_pFont9, g_pSprite9, NULL, NULL, 15 );

    D3DXCreateTexture(pd3dDevice, WIDTH, HEIGHT, 1, D3DUSAGE_DYNAMIC, D3DFMT_A32B32G32R32F, D3DPOOL_DEFAULT, &g_pFrameTexture);
    //V_RETURN(D3DXCreateTextureFromFileEx(pd3dDevice, L"..\\media\\textures\\hem.jpg", 
    //                                    D3DX_FROM_FILE, D3DX_FROM_FILE, 
    //                                    1, D3DUSAGE_DYNAMIC, D3DFMT_A32B32G32R32F, //D3DFMT_FROM_FILE
    //                                    D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, 0, 0, &g_pFrameTexture));

    g_HUD.SetLocation( pBackBufferSurfaceDesc->Width - 170, 0 );
    g_HUD.SetSize( 170, 170 );
    g_SampleUI.SetLocation( pBackBufferSurfaceDesc->Width - 170, pBackBufferSurfaceDesc->Height - 350 );
    g_SampleUI.SetSize( 170, 300 );

    return S_OK;
}


//--------------------------------------------------------------------------------------
// Handle updates to the scene.  This is called regardless of which D3D API is used
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext )
{
    //// Update the camera's position based on user input 
    //g_Camera.FrameMove( fElapsedTime );

    D3DLOCKED_RECT locked_rect;
    if( SUCCEEDED(g_pFrameTexture->LockRect(0, &locked_rect, 0, D3DLOCK_NO_DIRTY_UPDATE)))
    {
        int x = rand() % WIDTH;
        int y = rand() % HEIGHT;

        float* pPixel = (float*)locked_rect.pBits + locked_rect.Pitch*y/4 + x*4;
        pPixel[0] = 1.0f;

        g_pFrameTexture->UnlockRect(0);
    }
}


//--------------------------------------------------------------------------------------
// Render the scene using the D3D9 device
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D9FrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
{
    HRESULT hr;

    // If the settings dialog is being shown, then render it instead of rendering the app's scene
    if( g_SettingsDlg.IsActive() )
    {
        g_SettingsDlg.OnRender( fElapsedTime );
        return;
    }

    // Clear the render target and the zbuffer 
    V( pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB( 0, 45, 50, 170 ), 1.0f, 0 ) );

    // Render the scene
    if( SUCCEEDED( pd3dDevice->BeginScene() ) )
    {
        //if( SUCCEEDED(g_pSpriteTex->Begin(D3DXSPRITE_DO_NOT_ADDREF_TEXTURE|D3DXSPRITE_DONOTSAVESTATE|D3DXSPRITE_DONOTMODIFY_RENDERSTATE|D3DXSPRITE_BILLBOARD )))
        if( SUCCEEDED(g_pSpriteTex->Begin(0)))
        {
            D3DXMATRIX mat;
            D3DXMatrixTransformation2D(&mat, 0, 1, 0, 0, 0, 0);

            g_pSpriteTex->SetTransform(&mat);
            V(g_pSpriteTex->Draw(g_pFrameTexture, 0,0,0,0xFFFFFFFF ));
            g_pSpriteTex->End();
        }

        DXUT_BeginPerfEvent( DXUT_PERFEVENTCOLOR, L"HUD / Stats" ); // These events are to help PIX identify what the code is doing
        RenderText(fTime, fElapsedTime);
        V( g_HUD.OnRender( fElapsedTime ) );
        V( g_SampleUI.OnRender( fElapsedTime ) );
        DXUT_EndPerfEvent();

        V( pd3dDevice->EndScene() );
    }


}


//--------------------------------------------------------------------------------------
// Handle messages to the application
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing,
                          void* pUserContext )
{
    // Pass messages to dialog resource manager calls so GUI state is updated correctly
    *pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam );
    if( *pbNoFurtherProcessing )
        return 0;

    // Pass messages to settings dialog if its active
    if( g_SettingsDlg.IsActive() )
    {
        g_SettingsDlg.MsgProc( hWnd, uMsg, wParam, lParam );
        return 0;
    }

    // Give the dialogs a chance to handle the message first
    *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
    if( *pbNoFurtherProcessing )
        return 0;
    *pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
    if( *pbNoFurtherProcessing )
        return 0;

    return 0;
}


//--------------------------------------------------------------------------------------
// Handle key presses
//--------------------------------------------------------------------------------------
void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext )
{
}


//--------------------------------------------------------------------------------------
// Handles the GUI events
//--------------------------------------------------------------------------------------
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext )
{
    switch( nControlID )
    {
        case IDC_TOGGLEFULLSCREEN:
            DXUTToggleFullScreen(); break;
        case IDC_TOGGLEREF:
            DXUTToggleREF(); break;
        case IDC_CHANGEDEVICE:
            g_SettingsDlg.SetActive( !g_SettingsDlg.IsActive() ); break;
    }
}


//--------------------------------------------------------------------------------------
// Release D3D9 resources created in the OnD3D9ResetDevice callback 
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D9LostDevice( void* pUserContext )
{
    g_DialogResourceManager.OnD3D9LostDevice();
    g_SettingsDlg.OnD3D9LostDevice();
    if( g_pFont9 ) g_pFont9->OnLostDevice();
    if( g_pEffect9 ) g_pEffect9->OnLostDevice();
    SAFE_RELEASE( g_pSprite9 );
    SAFE_RELEASE( g_pSpriteTex );
    SAFE_DELETE( g_pTxtHelper );
    SAFE_RELEASE( g_pFrameTexture);

}


//--------------------------------------------------------------------------------------
// Release D3D9 resources created in the OnD3D9CreateDevice callback 
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D9DestroyDevice( void* pUserContext )
{
    g_DialogResourceManager.OnD3D9DestroyDevice();
    g_SettingsDlg.OnD3D9DestroyDevice();
    SAFE_RELEASE( g_pEffect9 );
    SAFE_RELEASE( g_pFont9 );
    SAFE_RELEASE( g_pFrameTexture);
}


////////////////////////////////////////////////////////////////////////
// Set up film, camera and scene
/////////////////////////////////////////////////////////////////////////
void ParseSceneFile(WCHAR* filename)
{
	FILE *fp = _wfopen(filename, L"r");

	WCHAR strCommand[MAX_PATH];

	while(fwscanf(fp, L"%s", strCommand) != EOF)
	{
		// camera setting
		if(0 == wcscmp(strCommand, L"camera"))
		{
			WCHAR type[MAX_PATH];
			fwscanf(fp, L"%s\n", type);
			if( 0 == wcscmp(type, L"pinhole"))
			{
				D3DXVECTOR3 eye, at, sky;
				fwscanf(fp, L"eye %f %f %f\n", &eye.x, &eye.y, &eye.z);
				fwscanf(fp, L"at %f %f %f\n", &at.x, &at.y, &at.z);
				fwscanf(fp, L"sky %f %f %f\n", &sky.x, &sky.y, &sky.z);
				float vfov, nearClip, farClip;
				fwscanf(fp, L"vertical fov degree %f\n", &vfov);
				fwscanf(fp, L"nearClip %f\n", &nearClip);
				fwscanf_s(fp, L"farClip %f\n", &farClip);
				
				// set up camera parameter
				g_ProjectCamera.SetCameraParameter(&eye, &at, &sky, vfov, nearClip, farClip, &g_Film);
			}
			else if(0 == wcscmp(type, L"finiteaperture"))
			{
				D3DXVECTOR3 eye, at, sky;
				fwscanf(fp, L"eye %f %f %f\n", &eye.x, &eye.y, &eye.z);
				fwscanf(fp, L"at %f %f %f\n", &at.x, &at.y, &at.z);
				fwscanf(fp, L"sky %f %f %f\n", &sky.x, &sky.y, &sky.z);
				
				float vfov, nearClip, farClip;
				fwscanf(fp, L"vertical fov degree %f\n", &vfov);
				fwscanf(fp, L"nearClip %f\n", &nearClip);
				fwscanf_s(fp, L"farClip %f\n", &farClip);
				
				float focalDepth, lensRadius;
				UINT numLensSamples;
				fwscanf(fp, L"lens radius %f\n", &lensRadius);
				fwscanf(fp, L"focal depth %f\n", &focalDepth);
				fwscanf_s(fp, L"number of lens samples %d\n", &numLensSamples);

				// set up camera parameter
				g_ProjectCamera.SetCameraParameter(&eye, &at, &sky, vfov, nearClip, farClip, &g_Film, lensRadius, focalDepth, numLensSamples);

			}
			else
			{
				::MessageBoxW(0, L"Unknown camera type", L"Error", 0);
			}
		}
		// film
		else if(0 == wcscmp(strCommand, L"film"))
		{
			UINT resX, resY;

			int i = fwscanf(fp, L" resolution %d %d\n", &resX, &resY);
			g_Film.InitialFilm(resX, resY);
		}
		// scene object
		else if(0 == wcscmp(strCommand, L"obj"))
		{
			WCHAR OBJFileName[MAX_PATH];
			D3DXVECTOR3 translation; // translation 
			D3DXVECTOR3 rotation;	 // rotation
			float scale	;			 // scale
			fwscanf(fp, L"%s\n", OBJFileName);
			fwscanf(fp, L"translation %f %f %f\n", &translation.x, &translation.y, &translation.z);
			fwscanf(fp, L"rotation %f %f %f\n", &rotation.x, &rotation.y, &rotation.z);
			rotation *= D3DX_PI/180;
			fwscanf(fp, L"scale %f\n", &scale);
			CModelOBJ* model = new CModelOBJ();
			model->Create(OBJFileName, &g_ImageLoader);
			model->ScaleRotateTranslate(scale, rotation, translation);
			g_SceneManager.AddModel(model);
		}
		// scene light
		else if(0 == wcscmp(strCommand, L"light"))
		{
			WCHAR type[MAX_PATH];
			fwscanf(fp, L"%s\n", type);
			if( 0 == wcscmp(type, L"point"))
			{
				D3DXVECTOR3 position, ambient, diffuse, specular;
				fwscanf(fp, L"position %f %f %f\n", &position.x, &position.y, &position.z);
				fwscanf(fp, L"ambient %f %f %f\n", &ambient.x, &ambient.y, &ambient.z);
				fwscanf(fp, L"diffuse %f %f %f\n", &diffuse.x, &diffuse.y, &diffuse.z);
				fwscanf(fp, L"specular %f %f %f\n", &specular.x, &specular.y, &specular.z);
				
				PointLightSource* light = new PointLightSource();
				light->position = position;
				light->ambient = ambient;
				light->diffuse = diffuse;
				light->specular = specular;
				g_SceneManager.AddPointLight(light);
			}
			else if( 0 == wcscmp(type, L"area"))
			{
				int numSamples;
				float width, height;
				D3DXVECTOR3 rotation, translation, color;

				fwscanf(fp, L"width %f height %f\n", &width, &height);
				fwscanf(fp, L"rotation %f %f %f\n", &rotation.x, &rotation.y, &rotation.z);
				fwscanf(fp, L"translation %f %f %f\n", &translation.x, &translation.y, &translation.z);
				fwscanf(fp, L"color %f %f %f\n", &color.x, &color.y, &color.z);
				fwscanf(fp, L"number of samples %d\n", &numSamples);

				AreaLightSource* light = new AreaLightSource();
				light->InitAreaLight(width, height, rotation, translation, color, numSamples);
				g_SceneManager.AddAreaLight(light);
			}

		}
		else
		{
			// other command we don't care, extract and throw away the line
			fgetws(strCommand, MAX_PATH, fp);
		}

	}

	g_SceneManager.SetupKDTree();

	fclose(fp);
}